package easyexcel

import (
	"github.com/xuri/excelize/v2"
	"io"
)

type ReadExcelStream[T any] interface {

	// SheetName 配置工作簿名称
	SheetName(sheetName string) ReadExcelStream[T]

	// TimeFormat 配置时间格式化
	TimeFormat(timeFormat string) ReadExcelStream[T]

	// BatchSize 配置批处理大小
	BatchSize(batchSize int) ReadExcelStream[T]

	// ReadLocal 从本地文件读取excel，读取一批数据转化为bean列表并调用handler函数处理
	// fileName - 本地文件路径
	// handler - 处理bean列表的函数
	ReadLocal(fileName string, handler func(beans []T))

	// ReadNet 从网络文件读取excel，读取一批数据转化为bean列表并调用handler函数处理
	// reader - 实现io.Reader接口的对象
	// handler - 处理bean列表的函数
	ReadNet(reader io.Reader, handler func(beans []T))
}

type excelToBeanStream[T any] struct {
	*easyExcel[T]
	readIdx   int
	batchSize int
}

// TimeFormat 配置时间格式化
func (tb *excelToBeanStream[T]) initToBeanStream() {
	tb.initEasyExcel()
	tb.readIdx = 1
	tb.batchSize = 100
}

// BatchSize 配置批处理大小
func (tb *excelToBeanStream[T]) BatchSize(batchSize int) ReadExcelStream[T] {
	if batchSize <= 0 {
		panic("batch size must be large 0")
	}
	tb.batchSize = batchSize
	return tb
}

// TimeFormat 配置时间格式化
func (tb *excelToBeanStream[T]) TimeFormat(timeFormat string) ReadExcelStream[T] {
	tb.setTimeFormat(timeFormat)
	return tb
}

// SheetName 配置sheet name
func (tb *excelToBeanStream[T]) SheetName(sheetName string) ReadExcelStream[T] {
	tb.setSheetName(sheetName)
	return tb
}

// ReadLocal 从本地文件读取excel
func (tb *excelToBeanStream[T]) ReadLocal(fileName string, handler func(beans []T)) {
	if fileName == "" {
		panic("excel文件名不能为空")
	}

	file, err := excelize.OpenFile(fileName)
	if err != nil {
		panic(err)
	}
	defer func() {
		// 关闭工作簿
		if err := file.Close(); err != nil {
			panic(err)
		}
	}()

	tb.read(file, handler)
}

// ReadNet 从网络文件读取excel
func (tb *excelToBeanStream[T]) ReadNet(reader io.Reader, handler func(beans []T)) {
	file, err := excelize.OpenReader(reader)
	if err != nil {
		panic(err)
	}
	defer func() {
		// 关闭工作簿
		if err := file.Close(); err != nil {
			panic(err)
		}
	}()

	tb.read(file, handler)
}

func (tb *excelToBeanStream[T]) read(file *excelize.File, handler func(beans []T)) {
	rows, err := file.Rows(tb.sheetName)
	if err != nil {
		panic(err)
	}
	defer func() {
		if err = rows.Close(); err != nil {
			panic(err)
		}
	}()

	beans := make([]T, 0, tb.batchSize)
	for rows.Next() {
		row, err := rows.Columns()
		if err != nil {
			panic(err)
		}

		// excel的实际表头信息
		if tb.readIdx == 1 {
			tb.titles = append(tb.titles, row...)
			tb.readIdx++
			continue
		}

		// 解析excel数据信息
		bean := tb.rows2Bean(file, row, tb.readIdx)
		beans = append(beans, bean)
		if len(beans) == tb.batchSize {
			handler(beans)
			beans = make([]T, 0, tb.batchSize)
		}
		tb.readIdx++
	}

	if len(beans) > 0 && len(beans) < tb.batchSize {
		handler(beans)
	}
}
